/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.gbvbahia.projeto.web.cadastro;

import br.com.gbvbahia.projeto.beans.facade.interfaces.GrupoFacade;
import br.com.gbvbahia.projeto.beans.facade.interfaces.UsuarioFacade;
import br.com.gbvbahia.projeto.entidades.Grupo;
import br.com.gbvbahia.projeto.entidades.Usuario;
import br.com.gbvbahia.projeto.exceptions.EntityException;
import br.com.gbvbahia.projeto.web.jsfutil.JsfUtil;
import br.com.gbvbahia.utils.MensagemUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import org.apache.log4j.Logger;

/**
 * CRUD Usuário.
 *
 * @author Guilherme
 * @since 2012/02/22
 */
@ManagedBean
@ViewScoped
public class UsuarioController extends EntityController<Usuario>
        implements Serializable {

    /**
     * Registra os eventos para debug em desenvolvimento.
     */
    private Logger logger = Logger.getLogger(UsuarioController.class);
    /**
     * Facade injetado pelo Spring para CRUD com usuário. <br> <b>Não
     * pode faltar setter para a injeção ocorrer</b>
     */
    @ManagedProperty("#{usuarioFacade}")
    private UsuarioFacade usuarioFacade;
    /**
     * Facade injetado pelo Spring para CRUD com Grupo. <b>Não pode
     * faltar setter para a injeção ocorrer</b>
     */
    @ManagedProperty("#{grupoFacade}")
    private GrupoFacade grupoFacade;
    /**
     * Filtro na tabela de usuários por primeiro nome.
     */
    private String nome;
    /**
     * Filtro na tabela de usuários por login.
     */
    private String login;
    /**
     * Utilizado para alteração de senha.
     */
    private String senha;
    /**
     * Usuário que está sendo atualizado, criado ou apagado.
     */
    private Usuario current;

    /**
     * Construtor padrão.
     */
    public UsuarioController() {
    }

    //====================
    //Iniciadores
    //====================
    /**
     * Executado após o bean JSF ser criado.
     */
    @PostConstruct
    public void init() {
        logger.info("init()...");
    }

    /**
     * Executado antes do bean JSF ser destruído.
     */
    @PreDestroy
    public void end() {
        logger.info("end()...");
    }

    //====================
    //Métodos Sobrescritos
    //====================
    @Override
    public String clean() {
        super.clean();
        this.senha = null;
        return JsfUtil.MANTEM;
    }

    @Override
    public EntityPagination getPagination() {
        if (pagination == null) {
            pagination = new EntityPagination() {

                @Override
                public int getItemsCount() {
                    return getFacade().contarPorNome(nome, login);
                }

                @Override
                public DataModel createPageDataModel() {
                    return new ListDataModel(getFacade().buscarUsuarioPorNomeLogin(nome, login,
                            new int[]{getPageFirstItem(), getPageFirstItem()
                                + getPageSize()}));
                }
            };
        }
        return pagination;
    }

    @Override
    protected String create() {
        try {
            current.setPass(senha);
            getFacade().create(current);
            MensagemUtils.messageFactoringFull("UsuarioCreated",
                    new Object[]{current.getUserId()},
                    FacesMessage.SEVERITY_INFO,
                    FacesContext.getCurrentInstance());
            recreateTable();
            return clean();
        } catch (EntityException ex) {
            MensagemUtils.messageFactoringFull(ex.getMessage(),
                    ex.getVariacoes(), FacesMessage.SEVERITY_ERROR,
                    FacesContext.getCurrentInstance());
            logger.info("Erro de criacao de usuário: "
                    + current.getUserId(), ex);
            return JsfUtil.MANTEM;
        }
    }

    @Override
    protected String update() {
        try {
            current.setPass(senha);
            getFacade().update(current);
            MensagemUtils.messageFactoringFull("UsuarioUpdated",
                    new Object[]{current.getFirstName()},
                    FacesMessage.SEVERITY_INFO,
                    FacesContext.getCurrentInstance());
            recreateTable();
            return clean();
        } catch (EntityException ex) {
            MensagemUtils.messageFactoringFull(ex.getMessage(),
                    ex.getVariacoes(), FacesMessage.SEVERITY_ERROR,
                    FacesContext.getCurrentInstance());
            logger.info("Erro de atualização de usuário: "
                    + current.getUserId(), ex);
            return JsfUtil.MANTEM;
        }
    }

    @Override
    protected void performDestroy() {
        try {
            getFacade().remove(current);
            MensagemUtils.messageFactoringFull("UsuarioDeleted",
                    new Object[]{current.getFirstName()},
                    FacesMessage.SEVERITY_INFO,
                    FacesContext.getCurrentInstance());
            clean();
        } catch (EntityException ex) {
            MensagemUtils.messageFactoringFull(ex.getMessage(),
                    ex.getVariacoes(), FacesMessage.SEVERITY_ERROR,
                    FacesContext.getCurrentInstance());
            logger.info("Erro de remoção de usuário: "
                    + current.getUserId(), ex);
        }
    }

    @Override
    public void setEntity(final Usuario t) {
        this.current = t;
    }

    @Override
    protected Usuario getNewEntity() {
        return new Usuario();
    }

    //====================
    //Métodos Filtros Paginação
    //====================
    /**
     * Retorna o login utilizado para filtro na paginação.
     *
     * @return nome java.lang.String
     */
    public String getLogin() {
        return login;
    }

    /**
     * Define o login do Usuário para filtrar na paginação.
     *
     * @param loginParam java.lang.String
     */
    public void setLogin(final String loginParam) {
        this.login = loginParam;
    }

    /**
     * Retorna o nome utilizado para filtro na paginação.
     *
     * @return nome java.lang.String
     */
    public String getNome() {
        return nome;
    }

    /**
     * Define o nome do Usuário para filtrar na paginação.
     *
     * @param nomeParam java.lang.String
     */
    public void setNome(final String nomeParam) {
        this.nome = nomeParam;
    }

    //====================
    // Select Itens
    //====================
    /**
     * Todos os Grupos para multipla escolha.
     *
     * @return Array de javax.faces.model.SelectItem
     */
    public SelectItem[] getGruposAvailableSelectMany() {
        return JsfUtil.getSelectItems(grupoFacade.findAll(), false,
                FacesContext.getCurrentInstance());
    }

    /**
     * Todos os Grupos para unica escolha.
     *
     * @return Array de javax.faces.model.SelectItem
     */
    public SelectItem[] getGruposAvailableSelectOne() {
        return JsfUtil.getSelectItems(grupoFacade.findAll(), true,
                FacesContext.getCurrentInstance());
    }
    //====================
    //Getters AND Setters
    //====================

    /**
     * O Facade que representa a entidade current.
     *
     * @return AbstractEntityBeans
     */
    public UsuarioFacade getFacade() {
        return usuarioFacade;
    }

    /**
     * O Facade que representa a entidade Grupo.
     *
     * @return AbstractEntityBeans
     */
    public GrupoFacade getEjbGrupoFacade() {
        return grupoFacade;
    }

    /**
     * Utilizado pelo JSF para realizar Injeção.
     *
     * @param facade Facade da camada de negócio.
     */
    public void setGrupoFacade(final GrupoFacade facade) {
        this.grupoFacade = facade;
    }

    /**
     * Utilizado pelo JSF para realizar Injeção.
     *
     * @param facade Facade da camada de negócio.
     */
    public void setUsuarioFacade(final UsuarioFacade facade) {
        this.usuarioFacade = facade;
    }

    /**
     * Usuário atual, pode ser null, pode ser um novo ou um já
     * existente.
     *
     * @return Usuario
     */
    public Usuario getCurrent() {
        return current;
    }

    /**
     * Primeira senha digitado pelo usuário. Deve ser igual a
     * senhaConfirm.
     *
     * @return java.lang.String
     */
    public String getSenha() {
        return senha;
    }

    /**
     * Define a senha do usuário. Deve ser igual a senhaConfirm.
     *
     * @param senhaParam java.lang.String
     */
    public void setSenha(final String senhaParam) {
        this.senha = senhaParam;
    }

    /**
     * SelectManyMenu do JSF não pode apontar para um SET, por isso
     * essa mascara para que funcione sem problemas.
     *
     * @return List com o grupos do usuário selecionado.
     */
    public List<Grupo> getGruposUserEdit() {
        if (current == null) {
            return null;
        }
        return new ArrayList<Grupo>(this.current.getGrupos());
    }

    /**
     * SelectManyMenu do JSF não pode apontar para um SET, por isso
     * essa mascara para que funcione sem problemas.
     *
     * @param gruposUserEdit Grupo selecionado na tela.
     */
    public void setGruposUserEdit(final List<Grupo> gruposUserEdit) {
        if (this.current != null) {
            this.current.setGrupos(new HashSet<Grupo>(gruposUserEdit));
        }
    }

    //====================
    // Conversor (Grupo)
    //====================
    /**
     * Conversor para Grupo.
     */
    @FacesConverter(forClass = Grupo.class, value = "grupoConverter")
    public static class GrupoControllerConverter implements Converter {

        /**
         *
         * @param facesContext Contexto JSF.
         * @param component Componente JSF que possui a entidade a ser
         * convertida.
         * @param value String que foi enviada pelo método
         * getAsString.
         * @return O objeto convertido em getAsString.
         */
        @Override
        public Object getAsObject(final FacesContext facesContext,
                final UIComponent component, final String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            UsuarioController controller =
                    JsfUtil.getController("usuarioController", facesContext);
            return controller.grupoFacade.find(value);
        }

        /**
         *
         * @param facesContext Contexto JSF.
         * @param component Componente JSF que possui a entidade a ser
         * convertida.
         * @param object Objeto a ser convertido em String para ir
         * para a tela do usuário.
         * @return String que representa o grupo, grupoId.
         */
        @Override
        public String getAsString(final FacesContext facesContext,
                final UIComponent component, final Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof Grupo) {
                Grupo o = (Grupo) object;
                return o.getGrupoId();
            } else {
                throw new IllegalArgumentException("object " + object
                        + " is of type " + object.getClass().getName()
                        + "; expected type: "
                        + UsuarioController.class.getName());
            }
        }
    }
    //====================
    // Conversor (Usuário)
    //====================

    /**
     * Conversor para classe Usuario em SelectItem.
     */
    @FacesConverter(forClass = Usuario.class, value = "usuarioConverter")
    public static class UsuarioControllerConverter implements Converter {

        /**
         * Devolve um Objeto Usuário com base nos parâmetros.
         *
         * @param facesContext Contexto atual.
         * @param component Componente SelectMany, SelectOne do JSF.
         * @param value Usuário em forma de String que deve ser
         * convertido em objeto. A string aqui é o login do usuário.
         * @return java.lang.Object que pode ser feito cast para
         * br.com.convergeti.solida.modelos.Usuario.
         */
        @Override
        public Object getAsObject(final FacesContext facesContext,
                final UIComponent component, final String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            UsuarioController controller =
                    JsfUtil.getController("usuarioController", facesContext);
            return controller.usuarioFacade.find(value);
        }

        /**
         * Retorna o objeto Usuário em formato de String, que
         * representa um Usuário.
         *
         * @param facesContext Contexto atual.
         * @param component Componente JSF que mostra o Usuário na
         * tela.
         * @param object Um br.com.convergeti.solida.modelos.Usuario.
         * @return java.lang.String, login Usuario toString.
         */
        @Override
        public String getAsString(final FacesContext facesContext,
                final UIComponent component, final Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof Usuario) {
                Usuario o = (Usuario) object;
                return o.getUserId();
            } else {
                throw new IllegalArgumentException("object " + object
                        + " is of type " + object.getClass().getName()
                        + "; expected type: "
                        + UsuarioController.class.getName());
            }
        }
    }
}
